#include "temp_module.h"
#include "log_module.h"
#include "alarm_module.h"
#include <rtdevice.h>
#include <rthw.h>

static temp_config_t *temp_config = RT_NULL;
static rt_thread_t temp_thread = RT_NULL;
static rt_spi_device_t cs1237_dev = RT_NULL;

/* CS1237 configuration registers */
typedef struct {
    uint8_t reg0;  /* Configuration register 0 */
    uint8_t reg1;  /* Configuration register 1 */
    uint8_t reg2;  /* Configuration register 2 */
} cs1237_registers_t;

/* Filter buffers for temperature data */
static struct {
    uint8_t index;
    uint8_t count;
    float buffer[10];
    float sum;
} temp_filters[TEMP_CHANNELS];

static void cd4052_select_channel(uint8_t channel)
{
    if (channel >= TEMP_CHANNELS) return;
    
    /* CD4052 truth table:
     * B A Channel
     * 0 0 0 (PT100-1)
     * 0 1 1 (PT100-2) 
     * 1 0 2 (NTC10K-1)
     * 1 1 3 (NTC10K-2)
     */
    rt_bool_t a_pin = (channel & 0x01) ? PIN_HIGH : PIN_LOW;
    rt_bool_t b_pin = (channel & 0x02) ? PIN_HIGH : PIN_LOW;
    
    rt_pin_write(CD4052_A_PIN, a_pin);
    rt_pin_write(CD4052_B_PIN, b_pin);
    
    /* Enable CD4052 (active low) */
    rt_pin_write(CD4052_INHIBIT_PIN, PIN_LOW);
}

static rt_err_t cs1237_spi_init(void)
{
    rt_err_t result;
    struct rt_spi_configuration cfg;
    
    /* Find SPI bus */
    struct rt_spi_bus *spi_bus = (struct rt_spi_bus *)rt_device_find("spi1");
    if (spi_bus == RT_NULL) {
        LOG_E("SPI1 bus not found\n");
        return RT_ERR_NOT_FOUND;
    }
    
    /* Configure SPI */
    cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB;  /* Mode 0, MSB first */
    cfg.max_hz = 1000000;                   /* 1MHz */
    cfg.data_width = 8;
    
    /* Create SPI device */
    cs1237_dev = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
    if (cs1237_dev == RT_NULL) {
        LOG_E("Failed to allocate CS1237 device\n");
        return RT_ERR_MEM;
    }
    
    result = rt_spi_bus_attach_device(cs1237_dev, "cs1237", "spi1", (void*)CS1237_CS_PIN);
    if (result != RT_OK) {
        LOG_E("Failed to attach CS1237 to SPI bus\n");
        rt_free(cs1237_dev);
        return result;
    }
    
    /* Configure device */
    result = rt_spi_configure(cs1237_dev, &cfg);
    if (result != RT_OK) {
        LOG_E("Failed to configure CS1237 SPI\n");
        rt_spi_bus_detach_device(cs1237_dev);
        rt_free(cs1237_dev);
        return result;
    }
    
    return RT_OK;
}

static void cs1237_gpio_init(void)
{
    /* Initialize CS1237 control pins */
    rt_pin_mode(CS1237_CS_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(CS1237_PDWN_PIN, PIN_MODE_OUTPUT);
    
    /* Initialize CD4052 control pins */
    rt_pin_mode(CD4052_A_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(CD4052_B_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(CD4052_INHIBIT_PIN, PIN_MODE_OUTPUT);
    
    /* Default states */
    rt_pin_write(CS1237_CS_PIN, PIN_HIGH);
    rt_pin_write(CS1237_PDWN_PIN, PIN_LOW);  /* Power up */
    rt_pin_write(CD4052_INHIBIT_PIN, PIN_HIGH); /* Disable initially */
}

static rt_err_t cs1237_reset(void)
{
    /* Reset CS1237 by toggling PDWN pin */
    rt_pin_write(CS1237_PDWN_PIN, PIN_HIGH);
    rt_thread_mdelay(10);
    rt_pin_write(CS1237_PDWN_PIN, PIN_LOW);
    rt_thread_mdelay(10);
    
    return RT_OK;
}

static rt_err_t cs1237_write_reg(uint8_t reg_addr, uint8_t reg_data)
{
    rt_err_t result;
    uint8_t tx_buf[3];
    uint8_t rx_buf[3];
    
    if (cs1237_dev == RT_NULL) {
        return RT_ERR_IO;
    }
    
    /* Command format: CMD(8bit) + REG_ADDR(8bit) + REG_DATA(8bit) */
    tx_buf[0] = CS1237_CMD_WRITE;
    tx_buf[1] = reg_addr;
    tx_buf[2] = reg_data;
    
    struct rt_spi_message msg;
    msg.send_buf = tx_buf;
    msg.recv_buf = rx_buf;
    msg.length = 3;
    msg.cs_take = 1;
    msg.cs_release = 1;
    msg.next = RT_NULL;
    
    result = rt_spi_transfer_message(cs1237_dev, &msg);
    if (result != RT_OK) {
        LOG_E("CS1237 write register failed\n");
    }
    
    return result;
}

static rt_err_t cs1237_read_reg(uint8_t reg_addr, uint8_t *reg_data)
{
    rt_err_t result;
    uint8_t tx_buf[3];
    uint8_t rx_buf[3];
    
    if (cs1237_dev == RT_NULL || reg_data == RT_NULL) {
        return RT_ERR_PARAM;
    }
    
    /* Command format: CMD(8bit) + REG_ADDR(8bit) + DUMMY(8bit) */
    tx_buf[0] = CS1237_CMD_READ;
    tx_buf[1] = reg_addr;
    tx_buf[2] = 0x00;
    
    struct rt_spi_message msg;
    msg.send_buf = tx_buf;
    msg.recv_buf = rx_buf;
    msg.length = 3;
    msg.cs_take = 1;
    msg.cs_release = 1;
    msg.next = RT_NULL;
    
    result = rt_spi_transfer_message(cs1237_dev, &msg);
    if (result == RT_OK) {
        *reg_data = rx_buf[2];  /* Data is returned in third byte */
    } else {
        LOG_E("CS1237 read register failed\n");
    }
    
    return result;
}

static int32_t cs1237_read_adc(void)
{
    rt_err_t result;
    uint8_t tx_buf[4] = {0};
    uint8_t rx_buf[4] = {0};
    int32_t adc_value = 0;
    
    if (cs1237_dev == RT_NULL) {
        return 0;
    }
    
    /* CS1237 data format: 24-bit signed, MSB first */
    struct rt_spi_message msg;
    msg.send_buf = tx_buf;
    msg.recv_buf = rx_buf;
    msg.length = 4;  /* 24-bit data + 8-bit status */
    msg.cs_take = 1;
    msg.cs_release = 1;
    msg.next = RT_NULL;
    
    result = rt_spi_transfer_message(cs1237_dev, &msg);
    if (result == RT_OK) {
        /* Combine 24-bit data (MSB first) */
        adc_value = (rx_buf[0] << 16) | (rx_buf[1] << 8) | rx_buf[2];
        
        /* Convert to signed 24-bit */
        if (adc_value & 0x00800000) {  /* Check sign bit */
            adc_value |= 0xFF000000;   /* Sign extend */
        }
    } else {
        LOG_E("CS1237 read ADC failed\n");
    }
    
    return adc_value;
}

static rt_err_t cs1237_configure(void)
{
    rt_err_t result;
    
    /* Configure CS1237 for temperature measurement */
    /* REG0: PGA=128, Speed=10Hz */
    result = cs1237_write_reg(0x00, 0x0C);
    if (result != RT_OK) return result;
    
    /* REG1: Temperature sensor mode */
    result = cs1237_write_reg(0x01, 0x01);
    if (result != RT_OK) return result;
    
    /* REG2: Default settings */
    result = cs1237_write_reg(0x02, 0x00);
    
    return result;
}

static float moving_average_filter(uint8_t channel, float new_value)
{
    if (temp_filters[channel].count < 10) {
        temp_filters[channel].buffer[temp_filters[channel].count] = new_value;
        temp_filters[channel].sum += new_value;
        temp_filters[channel].count++;
        return new_value;
    }
    
    /* Subtract oldest value */
    temp_filters[channel].sum -= temp_filters[channel].buffer[temp_filters[channel].index];
    
    /* Add new value */
    temp_filters[channel].buffer[temp_filters[channel].index] = new_value;
    temp_filters[channel].sum += new_value;
    
    /* Update index */
    temp_filters[channel].index = (temp_filters[channel].index + 1) % 10;
    
    return temp_filters[channel].sum / 10.0f;
}

static float adc_to_temperature_pt100(int32_t adc_value)
{
    /* PT100 conversion: RTD resistance to temperature */
    /* CS1237 with PGA=128, Vref=2.5V */
    float voltage = (adc_value / 8388608.0f) * 2.5f;  /* 24-bit signed */
    float current = 0.001f;  /* Assume 1mA excitation current */
    float resistance = voltage / current;
    
    /* PT100 temperature calculation using Callendar-Van Dusen equation */
    /* Simplified linear approximation for 0-100°C range */
    float temperature = (resistance - 100.0f) / 0.385f;
    
    return temperature;
}

static float adc_to_temperature_ntc10k(int32_t adc_value)
{
    /* NTC 10K thermistor conversion */
    /* Voltage divider with 10K resistor */
    float voltage = (adc_value / 8388608.0f) * 2.5f;
    float vcc = 3.3f;
    float r_series = 10000.0f;  /* 10K series resistor */
    
    /* Calculate thermistor resistance */
    float resistance = (voltage * r_series) / (vcc - voltage);
    
    /* Steinhart-Hart equation for NTC thermistor */
    /* Simplified B-parameter equation: 1/T = 1/T0 + 1/B * ln(R/R0) */
    float t0 = 298.15f;     /* 25°C in Kelvin */
    float r0 = 10000.0f;    /* Resistance at 25°C */
    float b_value = 3950.0f; /* B parameter */
    
    float t_kelvin = 1.0f / (1.0f/t0 + (1.0f/b_value) * log(resistance/r0));
    float temperature = t_kelvin - 273.15f;  /* Convert to Celsius */
    
    return temperature;
}

static float convert_adc_to_temperature(uint8_t channel, int32_t adc_value)
{
    float raw_temp;
    
    switch (temp_config->channels[channel].type) {
        case SENSOR_PT100:
            raw_temp = adc_to_temperature_pt100(adc_value);
            break;
        case SENSOR_NTC10K:
            raw_temp = adc_to_temperature_ntc10k(adc_value);
            break;
        default:
            raw_temp = 0.0f;
            break;
    }
    
    /* Apply linear calibration */
    raw_temp = linear_calibration(raw_temp, 
                                 temp_config->channels[channel].k_factor,
                                 temp_config->channels[channel].b_offset);
    
    /* Apply table calibration */
    if (temp_config->channels[channel].cal_table_size > 0) {
        raw_temp = table_calibration(raw_temp,
                                   temp_config->channels[channel].cal_table,
                                   temp_config->channels[channel].cal_table_size);
    }
    
    return raw_temp;
}

static void process_temp_message(message_t *msg)
{
    if (msg == RT_NULL) return;
    
    switch (msg->msg_type) {
        case MSG_CONTROL_CMD:
            /* Handle temperature control commands */
            break;
        default:
            break;
    }
}

rt_err_t temp_module_init(void)
{
    rt_err_t result;
    
    /* Get configuration pointer */
    temp_config = &g_system_config.temp;
    
    /* Initialize GPIO */
    cs1237_gpio_init();
    
    /* Initialize SPI */
    result = cs1237_spi_init();
    if (result != RT_OK) {
        LOG_E("CS1237 SPI initialization failed\n");
        return result;
    }
    
    /* Reset and configure CS1237 */
    cs1237_reset();
    result = cs1237_configure();
    if (result != RT_OK) {
        LOG_E("CS1237 configuration failed\n");
        return result;
    }
    
    /* Initialize filters */
    for (int i = 0; i < TEMP_CHANNELS; i++) {
        temp_filters[i].index = 0;
        temp_filters[i].count = 0;
        temp_filters[i].sum = 0.0f;
        rt_memset(temp_filters[i].buffer, 0, sizeof(temp_filters[i].buffer));
    }
    
    /* Create temperature thread */
    temp_thread = rt_thread_create("temp", 
                                  temp_thread_entry, 
                                  RT_NULL, 
                                  2048, 
                                  12, 
                                  20);
    if (temp_thread == RT_NULL) {
        LOG_E("Failed to create temperature thread\n");
        return RT_ERR_MEM;
    }
    
    LOG_I("Temperature module initialized successfully\n");
    return RT_OK;
}

void temp_thread_entry(void *parameter)
{
    rt_uint32_t tick;
    int32_t adc_value;
    float raw_temp, filtered_temp;
    
    while (1) {
        tick = rt_tick_get();
        
        /* Read all temperature channels */
        for (int i = 0; i < TEMP_CHANNELS; i++) {
            if (!temp_config->channels[i].enabled) {
                continue;
            }
            
            /* Select channel on CD4052 */
            cd4052_select_channel(i);
            rt_thread_mdelay(1);  /* Allow switching time */
            
            /* Read ADC value from CS1237 */
            adc_value = cs1237_read_adc();
            
            /* Convert to temperature */
            raw_temp = convert_adc_to_temperature(i, adc_value);
            
            /* Apply filter */
            filtered_temp = moving_average_filter(i, raw_temp);
            
            /* Update configuration */
            temp_config->channels[i].current_temp = filtered_temp;
            temp_config->channels[i].last_read_time = rt_tick_get();
        }
        
        /* Send data ready message */
        send_message(MODULE_PID, MSG_DATA_UPDATE, RT_NULL, 0);
        send_message(MODULE_ALARM, MSG_DATA_UPDATE, RT_NULL, 0);
        send_message(MODULE_MODBUS, MSG_DATA_UPDATE, RT_NULL, 0);
        
        /* Wait for next cycle */
        rt_thread_delay_until(&tick, rt_tick_from_millisecond(temp_config->base.update_interval));
    }
}

float temp_get_temperature(uint8_t channel)
{
    if (channel >= TEMP_CHANNELS || temp_config == RT_NULL) {
        return 0.0f;
    }
    
    return temp_config->channels[channel].current_temp;
}

rt_err_t temp_set_calibration(uint8_t channel, float k, float b)
{
    if (channel >= TEMP_CHANNELS || temp_config == RT_NULL) {
        return RT_ERR_PARAM;
    }
    
    temp_config->channels[channel].k_factor = k;
    temp_config->channels[channel].b_offset = b;
    
    LOG_I("Temperature channel %d calibration updated: k=%.3f, b=%.3f\n", 
          channel, k, b);
    
    return RT_OK;
}

rt_err_t temp_set_cal_table(uint8_t channel, cal_point_t *table, uint8_t size)
{
    if (channel >= TEMP_CHANNELS || temp_config == RT_NULL || table == RT_NULL) {
        return RT_ERR_PARAM;
    }
    
    if (size > 4) size = 4;
    
    rt_memcpy(temp_config->channels[channel].cal_table, table, size * sizeof(cal_point_t));
    temp_config->channels[channel].cal_table_size = size;
    
    LOG_I("Temperature channel %d calibration table updated, size=%d\n", channel, size);
    
    return RT_OK;
}

rt_err_t temp_select_sensor_type(uint8_t channel, sensor_type_t type)
{
    if (channel >= TEMP_CHANNELS || temp_config == RT_NULL) {
        return RT_ERR_PARAM;
    }
    
    temp_config->channels[channel].type = type;
    
    LOG_I("Temperature channel %d sensor type set to %d\n", channel, type);
    
    return RT_OK;
}

temp_config_t *temp_get_config(void)
{
    return temp_config;
}